package de.dhbw.karlsruhe.picsim.model.timer;

import de.dhbw.karlsruhe.picsim.model.cpu.ReadOnlyFile;
import de.dhbw.karlsruhe.picsim.model.memory.RegisterValue;
import de.dhbw.karlsruhe.picsim.util.Bits;
import de.dhbw.karlsruhe.picsim.util.impl.BitUtilities;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;

/**
 * Created by IntelliJ IDEA.
 * User: goesen
 * Date: Apr 28, 2010
 * Time: 7:14:40 PM
 */
final class PreScaler extends TimerSupport implements ResetAbleTimer {
    private static final Log log = LogFactory.getLog(PreScaler.class);
    private final ReadOnlyFile option;
    private int i;

    PreScaler(@NotNull final ReadOnlyFile option) {
        this.option = option;
        i = 0;
    }

    @Override
    public void reset() {
        log.info("The PreScaler was resetted on value=" + i);
        i = 0;

    }

    @Override
    public void increment() {
        final int maxValue = getMaxValue();
        i++;
        if (i >= maxValue) {
            log.info("preScaler timed out, because " + i + ">=" + maxValue);
            fireTimeout();
            reset();

        }
    }


    /*
      P15
     PSA: Prescaler Assignment bit
        1 = Prescaler assigned to the WDT
        0 = Prescaler assigned to TMR0
        bit 3:
        bit 2-0: PS2:PS0: Prescaler Rate Select bits

        Bit Value  TMR0 Rate    WDT Rate
        000           1:2          1:1
        001           1:4          1:2
        010           1:8          1:4
        011           1 : 16       1:8
        100           1 : 32       1 : 16
        101           1 : 64       1 : 32
        110           1 : 128      1 : 64
        111           1 : 256      1 : 128
    */

    private int getMaxValue() {
        final RegisterValue value = option.getData();
        final Bits bits = BitUtilities.subBits(value, 0, 3);
        final boolean isWatchdog = value.isSet(3);
        final int shiftWidth = isWatchdog
                ? BitUtilities.fromLeastSignificantBitFirst(bits)
                : BitUtilities.fromLeastSignificantBitFirst(bits) + 1;
        return Integer.rotateLeft(1, shiftWidth);

    }

}
